﻿
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;

namespace WSU.ChekaParallel.TestThread.Collection
{
    static class TestProdConsQueue
    {
        private static void SimpleTest()
        {
            Task[] producers = new Task[3];
            Task<int>[] consumers = new Task<int>[4];
            BlockingCollection<string> queue = new BlockingCollection<string>();

            // ------------------- spawn the producers
            for (int prod = 0; prod < producers.Length; ++prod)
            {
                producers[prod] = Task.Factory.StartNew(state =>
                {
                    for (int index = 0; index < 5; ++index)
                        queue.Add(string.Format("{0}-{1}", state, index));
                }, string.Format("producer{0}", prod + 1));
            }// iterate over each producer

            // chekanote: according to MSDN, call "CompleteAdding" make the whole BlockingCollection unable to add
            // NOT just forbid the thread which call "CompleteAdding" to add any more
            // BUT forbid all thread to add extra products into that blocking collection
            // so here "CompleteAdding" cannot be invoked when a single producer finishes, but should wait until
            // all the producers finish
            Task.Factory.ContinueWhenAll(producers, tasks => queue.CompleteAdding());

            // ------------------- spawn the consumers
            for (int cons = 0; cons < consumers.Length; cons++)
            {
                consumers[cons] = Task.Factory.StartNew(state =>
                {
                    int counter = 0;
                    foreach (string msg in queue.GetConsumingEnumerable())
                    {
                        Console.WriteLine("{0} takes '{1}'", state, msg);
                        ++counter;
                    }
                    return counter;
                }, string.Format("consumer{0}", cons + 1));
            }

            // ------------------- result statistics
            Task.WaitAll(consumers);
            Console.WriteLine("*********************************************");
            foreach (Task<int> consumer in consumers)
            {
                Console.WriteLine("{0} totally consumes {1} products", consumer.AsyncState, consumer.Result);
            }
        }

        public static void TestMain()
        {
            SimpleTest();
        }
    }
}